package com.pengzy.core.security;

import com.pengzy.comment.core.utils.JsonUtils;
import com.pengzy.comment.web.result.JsonResult;
import com.pengzy.comment.web.result.ServletUtils;
import com.pengzy.core.UserDetailsServiceImpl;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;

/**
 * @author xiaozhi 2023/7/7
 */

@Configuration
@EnableWebSecurity
//@EnableWebFluxSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)	// 启用方法级别的权限认证
@MapperScan(basePackages = {"com.pengzy.**.mapper","com.pengzy.**.**.mapper"})
public class SecuityConfig {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Resource
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    @Resource
    private AccessDeniedHandlerFilter accessDeniedHandlerFilter;



    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问（非remember-me下自动登录）
     * hasAnyAuthority     |   如果有参数，参数表示权限，则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数，参数表示角色，则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数，参数表示权限，则其权限可以访问
     * hasIpAddress        |   如果有参数，参数表示IP地址，如果用户IP和参数匹配，则可以访问
     * hasRole             |   如果有参数，参数表示角色，则其角色可以访问
     * permitAll           |   用户可以任意访问csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        return http
                //关闭csrf
                .csrf().disable()
                //允许跨域
                .cors()
                .and()
                //不通过Session获取SecurityContext,基于token
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                //把token校验过滤器添加到过滤器链中
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling(ex->
                        //配置AccessDeniedException过滤器会导致下面异常过滤器失效
                        ex.authenticationEntryPoint(jwtAuthenticationEntryPoint)
                                .accessDeniedHandler(accessDeniedHandlerFilter)
                )
                .authorizeRequests(ath->
                                // 允许对于网站静态资源的无授权访问
                                ath.antMatchers(HttpMethod.GET,
                                        "/",
                                        "/*.html",
                                        "/favicon.ico",
                                        "/**/*.html",
                                        "/**/*.css",
                                        "/**/*.js",
                                        "/swagger-resources/**",
                                        "/swagger/**",
                                        "/webjars/**",
                                        "/excel/**",
                                        "/log/**",
                                        "/v2/api-docs/**",
                                        "/doc.html"
                                ).permitAll()
                                        .antMatchers("/").permitAll()
                                        // 对于登录接口 允许匿名访问
                                        .antMatchers("/**/login").permitAll()
                                        .antMatchers("/core/register").permitAll()
//                        .antMatchers("/system/**").hasAnyRole("vip2","vip3")
                                        // 除上面外的所有请求全部需要鉴权认证
                                        .anyRequest().authenticated()
                )
                //没有权限转到login界面
//               .formLogin().loginPage("/core/login")
//                .and()
                //注销
                .logout().logoutUrl("/loginOut")
                .logoutSuccessHandler((req, resp, authentication) -> {
                    ServletUtils.renderString(resp, JsonUtils.toJsonString(JsonResult.success("退出成功！")));
                })
                .and()
                //重写校验
                .userDetailsService(userDetailsService)
                .build();
    }

    /**
     * 密码加密存储
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //配置跨源访问(CORS)
    @Bean
    public CorsConfigurationSource corsConfigurationSource(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfig = new CorsConfiguration ();

        // 允许所有请求方法
        corsConfig.addAllowedMethod ("*");
        // 允许所有域，当请求头
        corsConfig.addAllowedOrigin ("*");
        // 允许全部请求头
        corsConfig.addAllowedHeader ("*");
        // 允许携带 Authorization 头
        corsConfig.setAllowCredentials (true);

        source.registerCorsConfiguration("/**",new CorsConfiguration().applyPermitDefaultValues());

        //source.registerCorsConfiguration("/**",corsConfig);
        return source;
    }

    @Bean
    public AuthenticationManager authenticationManagerBean(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}
